﻿// Behavior originally contributed by Chinajade.
//
// LICENSE:
// This work is licensed under the
//     Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// also known as CC-BY-NC-SA.  To view a copy of this license, visit
//      http://creativecommons.org/licenses/by-nc-sa/3.0/
// or send a letter to
//      Creative Commons // 171 Second Street, Suite 300 // San Francisco, California, 94105, USA.

#region Summary and Documentation
// QUICK DOX:
// TEMPLATE_QB.cs is a skeleton for creating new quest behaviors.
//
// Quest binding:
//      QuestId [REQUIRED if EscortCompleteWhen=QuestComplete; Default:none]:
//      QuestCompleteRequirement [Default:NotComplete]:
//      QuestInLogRequirement [Default:InLog]:
//              A full discussion of how the Quest* attributes operate is described in
//              http://www.thebuddyforum.com/mediawiki/index.php?title=Honorbuddy_Programming_Cookbook:_QuestId_for_Custom_Behaviors
//      QuestObjectiveIndex [REQUIRED if EventCompleteWhen=QuestObjectiveComplete]
//          [on the closed interval: [1..5]]
//          This argument is only consulted if EventCompleteWhen is QuestObjectveComplete.
//          The argument specifies the index of the sub-goal of a quest.
//
// Tunables (ideally, the profile would _never_ provide these arguments):
//      CombatMaxEngagementRangeDistance [optional; Default: 23.0]
//          This is a work around for some buggy Combat Routines.  If a targetted mob is
//          "too far away", some Combat Routines refuse to engage it for killing.  This
//          value moves the toon within an appropriate distance to the requested target
//          so the Combat Routine will perform as expected.
//
// THINGS TO KNOW:
//
#endregion


#region Examples
// EXAMPLE:
//     <CustomBehavior File="TEMPLATE_QB" />
#endregion


#region Usings
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Linq;
using CommonBehaviors.Actions;
using Honorbuddy.QuestBehaviorCore;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Profiles;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;
using Buddy.Coroutines;
using Styx.Common.Helpers;
#endregion


namespace Honorbuddy.Quest_Behaviors.q14296
{
	[CustomBehaviorFileName(@"Development\q14296")]
	public class q14296 : QuestBehaviorBase
	{

		#region Constructor and Argument Processing
        public q14296(Dictionary<string, string> args)
			: base(args)
		{
			for (int i = 0; i < TopCenters.Length; i++ )
			{
                double z = i + 1 != TopCenters.Length ? Teleports[i + 1].Z : Landing[i].Z;
				TopCenters[i] = GetTopCenter(Teleports[i], Landing[i], z);
			}

	        try
				{
					// NB: Core attributes are parsed by QuestBehaviorBase parent (e.g., QuestId, NonCompeteDistance, etc)
                    
					// Behavior-specific attributes...
                   // QuestId=14296;
                   // TerminateWhen = new UserDefinedExpression<bool>("TerminateWhen", stopstr);
				}

				catch (Exception except)
				{
					// Maintenance problems occur for a number of reasons.  The primary two are...
					// * Changes were made to the behavior, and boundary conditions weren't properly tested.
					// * The Honorbuddy core was changed, and the behavior wasn't adjusted for the new changes.
					// In any case, we pinpoint the source of the problem area here, and hopefully it can be quickly
					// resolved.
					QBCLog.Exception(except);
					IsAttributeProblem = true;
				}
		}


		// Variables for Attributes provided by caller


		protected override void EvaluateUsage_DeprecatedAttributes(XElement xElement)
		{
			//// EXAMPLE: 
			//UsageCheck_DeprecatedAttribute(xElement,
			//    Args.Keys.Contains("Nav"),
			//    "Nav",
			//    context => string.Format("Automatically converted Nav=\"{0}\" attribute into MovementBy=\"{1}\"."
			//                              + "  Please update profile to use MovementBy, instead.",
			//                              Args["Nav"], MovementBy));
		}

		protected override void EvaluateUsage_SemanticCoherency(XElement xElement)
		{
			//// EXAMPLE:
			//UsageCheck_SemanticCoherency(xElement,
			//    (!MobIds.Any() && !FactionIds.Any()),
			//    context => "You must specify one or more MobIdN, one or more FactionIdN, or both.");
			//
			//const double rangeEpsilon = 3.0;
			//UsageCheck_SemanticCoherency(xElement,
			//    ((RangeMax - RangeMin) < rangeEpsilon),
			//    context => string.Format("Range({0}) must be at least {1} greater than MinRange({2}).",
			//                  RangeMax, rangeEpsilon, RangeMin)); 
		}
		#endregion


        public WoWGameObject Conduit
		{
			get
			{//195365
                /*
[0,D:13.277027130127,LoS:False,PtC:14.1170787811279,SPD:14.1170787811279]
[1,D:74.9370651245117,LoS:False,PtC:1.70141173319264E+38,SPD:NaN]
                 */
               /* var t = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(r => r.Entry == 195365).OrderBy(r => r.Distance).Take(2).ToList();
                string s = "";
                for (int i = 0; i < t.Count; i++)
                {
                    s += string.Format("[{1},D:{2},LoS:{3},PtC:{4},SPD:{5}]{0}"
                        , Environment.NewLine
                        , i
                        , t[i].Distance
                        , t[i].InLineOfSight
                        , t[i].PathTraversalCost()
                        , t[i].SurfacePathDistance()
                        );
                }
                Loginfo(s);
                */
                var p = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(r => r.Entry == 195365 && !double.IsNaN(r.SurfacePathDistance())).OrderBy(r => r.Distance).FirstOrDefault();
                //Loginfo((t == null).ToString());
                return p;
                        
			}

		}

		//#region Private and Convenience variables
		// Add what you need here...
		private Pair<double, double>[] levels = new[]
			                                  {
				                                 /*0*/ new Pair<double, double>(double.MinValue,17)
												 /*1*/, new Pair<double, double>(17,21)
												 /*2*/, new Pair<double, double>(24,27)
												 /*3*/, new Pair<double, double>(30,33)
												 /*4*/, new Pair<double, double>(35,38)
												 /*5*/, new Pair<double, double>(61,64)
												 /*6*/, new Pair<double, double>(81,84)
												 /*7*/, new Pair<double, double>(87,90)
												 /*8*/, new Pair<double, double>(107,110)
												 /*9*/, new Pair<double, double>(119,122)
												 /*10*/, new Pair<double, double>(133,137)
												 /*11*/, new Pair<double, double>(158,double.MaxValue)
			                                  };

		private WoWPoint[] Teleports = new[]
			                               {
													 /*0*/ new WoWPoint(4831.11,-6427.08,0.202199)
				                                     /*1*/, new WoWPoint(4839.37, -6473.45, 18.93353)
				                                     /*2*/, new WoWPoint(4861.094, -6516.766, 25.95446)
				                                     /*3*/, new WoWPoint(4908.665, -6547.917, 31.56315)
				                                     /*4*/, new WoWPoint(4968.884, -6537.353, 36.49027)
				                                     /*5*/, new WoWPoint(4995.372, -6481.101, 62.88715)
				                                     /*6*/, new WoWPoint(4980.777, -6421.787, 82.71022)
				                                     /*7*/, new WoWPoint(4918.405, -6407.507, 88.68224)
				                                     /*8*/, new WoWPoint(4892.654, -6485.785, 108.7388)
				                                     /*9*/, new WoWPoint(4947.046, -6507.795, 120.8566)
				                                     /*10*/, new WoWPoint(4968.147, -6460.507, 135.2696)
			                               };
		private WoWPoint[] Landing = new[]
			                            {
				                            /*0*/ new WoWPoint(4844.365,-6438.635,19.7051)
											/*1*/, new WoWPoint(4850.905,-6496.282,25.9784)
											/*2*/, new WoWPoint(4888.036,-6536.865,31.72207)
											/*3*/, new WoWPoint(4931.491,-6545.563,37.90341)
											/*4*/, new WoWPoint(4988.607,-6501.311,63.10115)
											/*5*/, new WoWPoint(4995.419,-6448.412,82.72689)
											/*6*/, new WoWPoint(4947.625,-6407.849,88.76228)
                                            // 4899.499,-6435.726,121.721)
											/*7*/, new WoWPoint(4887.854,-6457.479,108.3055)
											/*8*/, new WoWPoint(4923.473,-6506.743,121.6271)
											/*9*/, new WoWPoint(4964.999,-6481.646,134.2293)
										   /*10*/, new WoWPoint(4945.205,-6454.078,160.6811)
			                            };

        private bool[] touchFlag = new bool[11];

#region tempregion

		private WoWPoint[] TopCenters = new WoWPoint[11];

		private WoWPoint _endTopPoint = new WoWPoint(0, 0, 0);
		private bool _isBehaviorDone;
		private Composite _root;

        private WoWPoint _startWaterLocation = new WoWPoint(4821.347,-6424.354,-0.9601928);

        private WoWPoint _startLocation = new WoWPoint(4841.055,-6445.607,19.5288);
        private WoWPoint _endTopLocation = new WoWPoint(4934.076,-6458.293,160.631);
                                                       // 4933.644" Y="-6458.418" Z="160.6297
		//#endregion


		#region Overrides of CustomForcedBehavior
		// DON'T EDIT THESE--they are auto-populated by Subversion
		public override string SubversionId { get { return "$Id: TEMPLATE_QB.cs 1764 2014-10-31 08:59:41Z hawker $"; } }
		public override string SubversionRevision { get { return "$Rev: 1764 $"; } }


		// CreateBehavior supplied by QuestBehaviorBase.
		// Instead, provide CreateMainBehavior definition.


		// Dispose provided by QuestBehaviorBase.


		// IsDone provided by QuestBehaviorBase.
		// Call the QuestBehaviorBase.BehaviorDone() method when you want to indicate your behavior is complete.


		public override void OnStart()
		{
			// Acquisition and checking of any sub-elements go here.
			// A common example:
			//     HuntingGrounds = HuntingGroundsType.GetOrCreate(Element, "HuntingGrounds", HuntingGroundCenter);
			//     IsAttributeProblem |= HuntingGrounds.IsAttributeProblem;
			
			// Let QuestBehaviorBase do basic initialization of the behavior, deal with bad or deprecated attributes,
			// capture configuration state, install BT hooks, etc.  This will also update the goal text.
			var isBehaviorShouldRun = OnStart_QuestBehaviorCore();

			// If the quest is complete, this behavior is already done...
			// So we don't want to falsely inform the user of things that will be skipped.
			if (isBehaviorShouldRun)
			{
				// Setup settings to prevent interference with your behavior --
				// These settings will be automatically restored by QuestBehaviorBase when Dispose is called
				// by Honorbuddy, or the bot is stopped.
				//CharacterSettings.Instance.HarvestHerbs = false;
				//CharacterSettings.Instance.HarvestMinerals = false;
				//CharacterSettings.Instance.LootChests = false;
				//CharacterSettings.Instance.NinjaSkin = false;
				//CharacterSettings.Instance.SkinMobs = false;


				// Setup the BehaviorFlags as needed --
				// These settings will be automatically restored by QuestBehaviorBase when Dispose is called
				// by Honorbuddy, or the bot is stopped.
				//LevelBot.BehaviorFlags &= ~BehaviorFlags.Combat;  // Turns off the Combat Routine, if needed
			}
		}
		#endregion


		#region TargetFilters
		// HBcore runs the TargetFilter_IncludeTargets after the TargetFilter_RemoveTargets.
		//protected override void TargetFilter_IncludeTargets(List<WoWObject> incomingWowObjects, HashSet<WoWObject> outgoingWowObjects)
		//{
		//    // empty--left for child to override
		//}


		// HBcore runs the TargetFilter_RemoveTargets before the TargetFilter_IncludeTargets.
		//protected override void TargetFilter_RemoveTargets(List<WoWObject> wowObjects)
		//{
		//    // empty--left for child to override
		//}


		// When scoring targets, a higher value of TargetPriority.Score makes the target more valuable.
		//protected override void TargetFilter_WeighTargets(List<Targeting.TargetPriority> targetPriorities)
		//{
		//    // empty--left for child to override
		//}
		#endregion


		#region Main Behaviors
		protected override Composite CreateBehavior_CombatMain()
		{
            return new ActionRunCoroutine(ctx => CombatMainCoroutine());
		}

        private async Task<bool> CombatMainCoroutine()
        {
            // TODO: Populate this...
            return false;
        }


		protected override Composite CreateBehavior_CombatOnly()
		{
            return new ActionRunCoroutine(ctx => CombatOnlyCoroutine());
		}

        private async Task<bool> CombatOnlyCoroutine()
        {
            // TODO: Populate this...
            return false;
        }


		protected override Composite CreateBehavior_DeathMain()
		{
            return new ActionRunCoroutine(ctx => DeathMainCoroutine());
		}

        private async Task<bool> DeathMainCoroutine()
        {
            // TODO: Populate this...
            return false;
        }

		/*private Composite FlyClose
		{
			get
			{
				return
					new Decorator(ret => !Me.IsOnTransport && (Orb == null || Orb.DistanceSqr > 5 * 5),
						new Action(r => Flightor.MoveTo(_orbLoc)));
			}
		}
		 
		private Composite Interact
		{
			get
			{
				return new PrioritySelector(
					ctx => Orb,
					new Decorator(
						ret => !Me.IsOnTransport && ret != null && ((WoWUnit)ret).Distance <= 5,
						new Sequence(
							new DecoratorContinue(ctx => Me.Mounted, 
								new Sequence(
                                    new ActionRunCoroutine(context => CommonCoroutines.Dismount("interacting with orb")),
									new WaitContinue(2, ctx => !Me.Mounted, new ActionAlwaysSucceed()))),
						new Action(ctx => ((WoWUnit)ctx).Interact()),                                    
						new WaitContinue(2, ctx => GossipFrame.Instance.IsVisible, new ActionAlwaysSucceed()),
						new Action(
							delegate
							{
								_exitTimer.Reset();
								Lua.DoString("SelectGossipOption(1)");
							}))));
			}
		}
		 */

		protected override Composite CreateBehavior_QuestbotMain()
		{
			return _root ?? (_root =
				new Decorator(ret => !_isBehaviorDone,
					new PrioritySelector(
						DoneYet,
						new Decorator(r => CanFly, FlyComposition),
						GroundComposition))
						);
		}

        public override void OnFinished()
        {
            base.OnFinished();
        }

        /*public new bool IsDone
        {
            get
            {
                return (_isBehaviorDone     // normal completion
                        || !UtilIsProgressRequirementsMet(QuestId, QuestRequirementInLog, QuestRequirementComplete));
            }
        }*/

		private Composite DoneYet
		{
			get
			{
				return
					new Decorator(ret => Me.IsQuestComplete(QuestId),
						new Action(delegate
						{
							TreeRoot.StatusText = "Finished!";
							_isBehaviorDone = true;
							return RunStatus.Success;
						}));
			}
		}

        private Composite FlyComposition
        {
            get
            {
                return new PrioritySelector(
                    
                    
                    );
            }
        }

        private Composite GroundComposition
        {
            get
            {
                return new PrioritySelector(
                    new Decorator(r => IsOnPinacle, FinalComposition)
                    , new Decorator(r => IsOnGround, WaterStartComposition)
					, new Decorator(r => IsOnFirstLevel, StartComposition)
                    , new Decorator(r => IsInTheSky, new Action(a=>
                        {
                            new Sleep(500);
                        }))
                    , new Decorator(r => IsOnLevels, JumpComposition)
                    
                    
                    );
            }
        }


        private Composite MyMoveTo(WoWPoint location, double range = 2)
        {
            
            return 
                    new PrioritySelector(
                           new Decorator(ret => (location.Distance(Me.Location) <= range) || (Me.Z - location.Z > 4.0f),
									new Action(ctx => {
                                       /* Loginfo(String.Format("MoveTo ({0},{1},{2}):{3}", location.X, location.Y, location.Z, range));
                                        if (location.Distance(Me.Location) <= range)
                                        {
                                            Loginfo(String.Format("1:dist={0},range={1}{2}", location.Distance(Me.Location),range, Environment.NewLine));
                                        }
                                        if (Me.Z - location.Z > 4.0f)
                                        {
                                            Loginfo(String.Format("2:Me.Z={0}, location.Z={1}, Diff={2}{3}", Me.Z, location.Z, Me.Z - location.Z, Environment.NewLine));
                                        }*/
                                        WoWMovement.MoveStop();
                                    }
                                        )
                           ),

                          new Action(ret => 
                              {
                                  //Loginfo(String.Format("MoveTo ({0},{1},{2}):{3}",location.X, location.Y,location.Z, range ) );
                                  if (location!= null)
                                    Navigator.MoveTo(location);
                              }
                          )
					);
        }

        private readonly WaitTimer _waitTimer = new WaitTimer(TimeSpan.Zero);
        private Composite FinalComposition
        {
            get
            {
                
                return new PrioritySelector(
                        new Decorator(ret => _waitTimer.IsFinished && !IsDone && QuestId == 14296,
                                new Sequence(
                                     new Action(a => Loginfo("Level: Pinnacle!")),
                                     MyMoveTo(new WoWPoint(4950,-6460.515,159), 1))
                                )
                            );
                  
            }
        }

        String _lastInfoMsg = "";
        private void Loginfo(string s)
        {
            if (_lastInfoMsg != s)
            {
                _lastInfoMsg = s;
                QBCLog.Info(_lastInfoMsg);
            }

        }

		private Composite WaterStartComposition
		{
			get
            {
                
                return new PrioritySelector(
                     new Decorator(r => Me.Location.Distance(Teleports[0]) > 30, 
                            new Sequence(
                                     new Action(a => Loginfo("Level: Water!")),
                                     new Action(a =>
                                         {
                                             /*
                                             RunLikeHell.RunLikeHell rh = new RunLikeHell.RunLikeHell(new Dictionary<string, string>());
                                             XElement xe = new XElement("Hotspot");
	                                         xe.SetAttributeValue("X", "4821.347");
											 xe.SetAttributeValue("Y", "-6424.354");
											 xe.SetAttributeValue("Z", "-0.9601928");

											 rh.Element.Add(xe);
											 rh.OnStart();    
											 */
                                             Loginfo("Level: Water!"); }
                                         
                                         ),

                                     MyMoveTo(_startWaterLocation))
                            ),
                     GotoTeleport(0)
                        );
			}
		}

        public const int Aura_ENERGIZED = 68613;
        //string stopstr = "Me.Z > 150";

        Composite GetNearENERGY
        {
            get
            {
                return new PrioritySelector( //ctx => Conduit,
                    new Decorator(r => (Conduit != null && Me.Location.Distance(Conduit.Location) > 5),
                    //new Action(r => Loginfo(String.Format("ENERGIZING. ID:{1},D:{0}", Me.Location.Distance(((WoWGameObject)r).Location), ((WoWGameObject)r).Entry)))
                            new PrioritySelector(
                                   new Decorator(ret => (Me.IsMoving && Conduit.Location.Distance(Me.Location) <= 5 ) || Me.Z - Conduit.Location.Z > 4.0f,
									        new Action(ctx => {
                                                WoWMovement.MoveStop();
                                            }
                                                )
                                   ),

                                  new Action(ctx => {
                                      //if (Conduit != null && Conduit.Location != null)
                                      WoWMovement.ClickToMove(Me.Location.ChangeByDistance(Conduit.Location, -2));
                                  })
					        )
                          )
                    , new Decorator(r => Conduit != null,
                            new Action(r => {
                                    var c = Conduit;
                                    if (Me.IsMoving) WoWMovement.MoveStop();
                                    if (c != null)
                                    {
                                        Me.SetFacing(c.Location);
                                        c.Interact();
                                    }
                                })
                        )
                        );
            }
        }
		private Composite StartComposition
		{
			get
            {
                return new PrioritySelector(
                    /*new Decorator(r => Me.QuestLog.GetQuestById(QuestId)== null,
                        
                        ),*/
                    new Decorator(r => QuestId == 14296 && (!Me.HasAura(Aura_ENERGIZED) || Me.GetAuraById(Aura_ENERGIZED).StackCount < 5), 
                        new Sequence(
                            new Action(a => Loginfo("ENERGIZING ")),
                            GetNearENERGY,
                            new Action(a => {
                                touchFlag[4]=touchFlag[8]=false;
                                if(Me.HasAura(Aura_ENERGIZED) && Me.GetAuraById(Aura_ENERGIZED).StackCount < 5)
                                    new Sleep(11000);
                            })

                                     )),
                         GotoTeleport(1)
                        );
                    
            }
		}

        private Sequence GotoTeleport(int level)
        {
            return new Sequence(
                                     new Action(a => Lua.DoString("Dismount()")),
                                     new Action(a => Loginfo("Level: " + level)),
                                     MyMoveTo(Teleports[level]),
                                     WaitForTP
                                        );
        }

        private Action WaitForTP
        {
            get
            {
                return new Action(a =>
                {
                    if (!Me.IsMoving)
                    {
                        Loginfo("Wait for TP!");
                        new Sleep(1000);
                    }
                });
            }
        }

		

        private Composite JumpComposition
        {
            get
            {
                return new PrioritySelector(
                         new Decorator(r => IsOnLevel(2), GotoTeleport(2))
                         ,new Decorator(r => IsOnLevel(3), GotoTeleport(3))
                         ,new Decorator(r => IsOnLevel(4), /*GotoTeleport(4))*/
                             new PrioritySelector(
                                 new Decorator(r => QuestId == 14296 && Me.GetAuraById(Aura_ENERGIZED).StackCount > 5 && !touchFlag[4],
                                    new Action(a => touchFlag[4] = true)),
                                new Decorator(r => QuestId == 14296 && !touchFlag[4], GetNearENERGY),
                                GotoTeleport(4)
                             ))
                         ,new Decorator(r => IsOnLevel(5), GotoTeleport(5))
                         , new Decorator(r => IsOnLevel(6), GotoTeleport(6))
                         , new Decorator(r => IsOnLevel(7), GotoTeleport(7))
                         , new Decorator(r => IsOnLevel(8),/* GotoTeleport(8))*/
                                new PrioritySelector(
                                     new Decorator(r => QuestId == 14296 && Me.GetAuraById(Aura_ENERGIZED).TimeLeft.Seconds > 20 && !touchFlag[8],
                                        new Action(a => touchFlag[8] = true)),
                                    new Decorator(r => QuestId == 14296 && !touchFlag[8], GetNearENERGY),
                                    GotoTeleport(8)
                                 ))
                         , new Decorator(r => IsOnLevel(9), GotoTeleport(9))
                         , new Decorator(r => IsOnLevel(10), /* GotoTeleport(10))*/
                                new Sequence(
                                    new Action(a => {
                                        _waitTimer.WaitTime = TimeSpan.FromMilliseconds(5000);
                                        _waitTimer.Reset();
                                    }),
                                    GotoTeleport(10)
                                 ))

                    );
            }
        }


		#endregion

        private double DefaultArrivalTolerance = 1;
        public bool CanFly { get { return Flightor.CanFly && !Navigator.CanNavigateWithin(Me.Location, _startLocation, (float)DefaultArrivalTolerance); } }

        public bool IsOnPinacle { get { return Me.Z > 158 && _endTopLocation.Distance2D(Me.Location) < 22; } }

        public bool IsInTheSky { get { return Me.Fleeing || Me.IsMoving || Me.IsFlying || Me.IsFalling; } }

        public bool IsOnLevels { get { return Me.Z > 23 && Me.Z < 159; } }

		public bool IsOnLevel(int level)
		{
			return Me.Z > levels[level].First && Me.Z < levels[level].Second && TopCenters[level].Distance2D(Me.Location) > 5;
		}

        public bool IsOnFirstLevel { get { return Me.Z > levels[1].First && Me.Z < levels[1].Second; } }

        public bool IsOnGround { get { return Me.Z < levels[0].Second || _endTopLocation.Distance2D(Me.Location) > 110; } }

		public WoWPoint GetTopCenter(WoWPoint a, WoWPoint b, double z)
		{
            var t = ObjectManager.GetObjectsOfType<WoWUnit>().Where(r => r.Entry == 35913 && r.Aggro).OrderBy(r => r.Distance).FirstOrDefault();
            var rn = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(r => r.Entry == 195661 && r.State == WoWGameObjectState.Active).OrderBy(r => r.Distance).FirstOrDefault();

            if (t != null && rn != null)
            {
                double dx = rn.X - t.X;
                double dy = rn.Y - t.Y;
                double l = Math.Sqrt(dx * dx + dy * dy);
                double sinA = dy / l;
                double cosA = dx / l;
                double n = l + 10;
                var c = new WoWPoint(t.X + n * cosA, t.Y + n * sinA, rn.Z);
                //Logging.Write(Colors.Green, "MoveTo ({0},{1},{2})", c.X, c.Y, c.Z)
                WoWMovement.ClickToMove(c);
            }
            else
            {
                //Logging.Write("No Souls/Runes");
            }

			return new WoWPoint((a.X + b.X)/2, (a.Y + b.Y)/2, z);
		}

		// Arcane Detonation Aura 68602 Distance 8
        // Arcane Detonation Bunny 35171
        // Arcane Credit Bunny 36408
#endregion
        /*
         <While Condition="(HasQuest(14296)) &amp;&amp; (!IsQuestCompleted(14296))">
				<If Condition="(!Me.Fleeing) &amp;&amp; (!Me.IsMoving) &amp;&amp; (!Me.IsFlying) &amp;&amp; (!Me.IsFalling)">
					<If Condition="(Me.Z &lt; 17)">
						<CustomBehavior File="Message" Text="Level: Water" LogColor="Green" />
						<RunTo QuestId="14296" X="4824.523" Y="-6423.504" Z="-1.019796" />
						<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" />
					</If>
					<If Condition="(Me.Z &gt; 17) &amp;&amp; (Me.Z &lt; 23)">
						<CustomBehavior File="Message" Text="Level: 1" LogColor="Green" />
						<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="12" Range="3" WaitForNpcs="False" WaitTime="100" />
						<RunTo QuestId="14296" />
						<CustomBehavior File="WaitTimer" WaitTime="950"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="500" X="4839.37" Y="-6473.45" Z="18.93353" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 23) &amp;&amp; (Me.Z &lt; 30)">
						<CustomBehavior File="Message" Text="Level: 2" LogColor="Green" />
						<!--<CustomBehavior File="WaitTimer" WaitTime="1000"/>-->
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="950"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="1500" X="4861.094" Y="-6516.766" Z="25.95446" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 30) &amp;&amp; (Me.Z &lt; 35)">
						<CustomBehavior File="Message" Text="Level: 3" LogColor="Green" />
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="25" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="500"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="2000" X="4908.665" Y="-6547.917" Z="31.56315" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 35) &amp;&amp; (Me.Z &lt; 60)">
						<CustomBehavior File="Message" Text="Level: 4" LogColor="Green" />
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="1500"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="2000" X="4968.884" Y="-6537.353" Z="36.49027" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 60) &amp;&amp; (Me.Z &lt; 80)">
						<CustomBehavior File="Message" Text="Level: 5" LogColor="Green" />
						<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="20" Range="3" WaitForNpcs="False" />
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="500"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="1000" X="4995.372" Y="-6481.101" Z="62.88715" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 80) &amp;&amp; (Me.Z &lt; 87)">
						<CustomBehavior File="Message" Text="Level: 6" LogColor="Green" />
						<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="500"/>
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="1000" X="4982.649" Y="-6425.561" Z="83.04372" IgnoreLoSToTarget="True" />-->
					</If>
					
					<If Condition="(Me.Z &gt; 87) &amp;&amp; (Me.Z &lt; 93)">
						<CustomBehavior File="Message" Text="Level: 7" LogColor="Green" />
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="2000"/>
						
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId1="196407" MobId2="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" 
							WaitTime="1000" X="4918.405" Y="-6407.507" Z="88.68224" IgnoreLoSToTarget="True" />-->
					</If>
					<If Condition="(Me.Z &gt; 87) &amp;&amp; (Me.Z &lt; 118)">
						<CustomBehavior File="Message" Text="Level: 8" LogColor="Green" />
						<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="500"/>
					</If>
					
					<If Condition="(Me.Z &gt; 118) &amp;&amp; (Me.Z &lt; 133)">
						<CustomBehavior File="Message" Text="Level: 9" LogColor="Green" />
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="500"/>
					</If>
					
					<If Condition="(Me.Z &gt; 133) &amp;&amp; (Me.Z &lt; 158)">
						<CustomBehavior File="Message" Text="Level: 10" LogColor="Green" />
						<!--<CustomBehavior File="InteractWith" QuestId="14296" MobId="195365" CollectionDistance="15" Range="3" WaitForNpcs="False" />-->
						<RunTo QuestId="14296" X="" />
						<CustomBehavior File="WaitTimer" WaitTime="1000"/>
					</If>
					
					
					<If Condition="(Me.Z &gt; 158)">
					<!--
					<GameObject Name="Скрытая энергия" Entry="196407" X="4899.538" Y="-6435.668" Z="121.7372" />
					<GameObject Name="Скрытая энергия" Entry="196407" X="4947.046" Y="-6507.795" Z="120.8566" />
					<GameObject Name="Скрытая энергия" Entry="195367" X="4968.147" Y="-6460.507" Z="135.2696" />
					
					-->
						<!--
						<Hotspot X="4922.496" Y="-6410.464" Z="89.01986" />
	<Hotspot X="4889.923" Y="-6484.054" Z="107.9105" />
						
						<CustomBehavior File="InteractWith" QuestId="14296" MobId="195367" CollectionDistance="10" Range="2" WaitForNpcs="False" />-->
					</If>
					<Else>
						<CustomBehavior File="Message" Text="I'm flying" LogColor="Blue" />
					</Else>
				</If>
			</While>
         
         */
       
    }

    public static class HQext
    {
        public static double DistanceXYSqr(this WoWPoint a, WoWPoint loc)
        {
            double l = loc.X - a.X;
            double h = loc.Y - a.Y;
            return l * l + h * h;
        }
        public static double DistanceXY(this WoWPoint a, WoWPoint loc)
        {
            return Math.Sqrt(DistanceXYSqr(a, loc));
        }

        public static WoWPoint ChangeByDistance(this WoWPoint a, WoWPoint loc, double dl)
        {
            double dx = loc.X - a.X;
            double dy = loc.Y - a.Y;
            double l = Math.Sqrt(dx * dx + dy * dy);
            double sinA = dy / l;
            double cosA = dx / l;
            double n = l + dl;

            return new WoWPoint(a.X + n * cosA, a.Y + n * sinA, loc.Z);
            
        }

    }

	public class Pair<T, U>
	{
		public Pair()
		{
		}

		public Pair(T first, U second)
		{
			this.First = first;
			this.Second = second;
		}

		public T First { get; set; }
		public U Second { get; set; }
	};
    
}